home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / dtr / canvas.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  32.8 KB  |  1,174 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/DTR/RCS/canvas.c,v 1.10 92/01/09 12:40:34 drapeau Exp Locker: derek $ */
  25. /* $Log:    canvas.c,v $
  26.  * Revision 1.10  92/01/09  12:40:34  drapeau
  27.  * > Slight modifications to the code to make it ANSI-compliant.
  28.  * 
  29.  * Revision 1.0  92/01/06  17:41:10  drapeau
  30.  * Made a number of cosmetic changes to make code easier to read and
  31.  * to conform to programming specifications.
  32.  * 
  33.  * Revision 0.26  91/09/18  22:47:14  derek
  34.  * The following things are done:
  35.  * 1.    The Makefile is changed corresponding to the changes in collab/.
  36.  * 2.    Copyright messages included.
  37.  * 3.    Some minor bugs fixed.
  38.  * 
  39.  * Revision 0.25  91/08/27  18:05:58  derek
  40.  * The SizeToFit bug is fixed.
  41.  * 
  42.  * Revision 0.24  91/08/27  17:22:25  derek
  43.  * The zooming bug is fixed in this version.
  44.  * 
  45.  * Revision 0.23  91/08/21  17:46:53  derek
  46.  * The big canvas "mis-placed" bug is fixed.
  47.  * 
  48.  * Revision 0.22  91/08/21  11:34:07  derek
  49.  * The following changes are made:
  50.  * 1.    Now the duration and size of the recorded sound will be displayed
  51.  *     during recording.
  52.  * 2.    I have changed GetSelection() corresponding to the request of Tek joo
  53.  * 3.    Info Panel is added to the application.
  54.  * 4.    Fixed SizeToFitHandler() so that when no file or buffer is currently
  55.  *     loaded, it would not do anything (except giving a warning
  56.  *     notice_prompt).
  57.  * 5.    Inplemented the `Close' Menu option in the document menu.
  58.  * 6.    Fixed the bug in which after ClearAll and I press PreviewEdit,
  59.  *     the edit wont be played.
  60.  * 7.    I have made the changes corresponding to the change in OpenPanel's
  61.  *     name.  (from OpenPanel to Browse).
  62.  * 8.    Incorporated BrowseCheck to check command line arg.
  63.  * 9.    Changed most EditingStatusMessages to NoticePrompts.
  64.  * 10.    SoundFileSaveAsPopUp and EditListSaveAsPopUp are removed 
  65.  *     from the application.
  66.  * 
  67.  * Revision 0.21  91/08/08  21:44:27  derek
  68.  * Fixed a number of bugs.
  69.  * 
  70.  * Revision 0.20  91/08/08  11:01:59  derek
  71.  * This is a cleaner version.  I have removed lots of printf/fprintf 
  72.  * statements from it, and have also cleaned up the code using xsaber.
  73.  * This version should run substantially faster.
  74.  * 
  75.  * Revision 0.19  91/08/07  16:23:55  derek
  76.  * The Edit list part of DTR is done.  OpenPanel is also incorporated.
  77.  * 
  78.  * Revision 0.18  91/08/06  12:41:05  derek
  79.  * Edit list panel is done.  Still need to link it to the network code.
  80.  * 
  81.  * Revision 0.17  91/07/29  15:10:07  derek
  82.  * The playing w/o stopping error is fixed.
  83.  * 
  84.  * Revision 0.16  91/07/26  13:18:12  derek
  85.  * Some saving bugs fixed.
  86.  * 
  87.  * Revision 0.15  91/07/24  12:51:48  derek
  88.  * Disk editing is done.  Now the application can record sound infinitely,
  89.  * as long as there is disk space available.  Command line args are also
  90.  * supported.
  91.  * 
  92.  * Revision 0.14  91/07/23  21:21:26  derek
  93.  * This version is not ready for release.  Disk space editing is half-done:
  94.  * the application can play an infinite sound and the canvases can handle
  95.  * infinite sound files.  The app is pretty bug free too, I think.  The
  96.  * weakness is that it cannot record sound infinitely.  
  97.  * 
  98.  * Revision 0.13  91/06/26  15:54:57  derek
  99.  * I have reformatted the code to conform coding specs.
  100.  * 
  101.  * Revision 0.12  91/06/20  19:55:15  derek
  102.  * The network part should be working.  Also fixed numerous minor parts
  103.  * involving the canvas and the display.
  104.  * 
  105.  * Revision 0.10  1991/04/25  01:45:11  derek
  106.  * This version is checked in on 4/24/91
  107.  * */
  108. static char rcsid[] = "$Header: /Source/Media/collab/DTR/RCS/canvas.c,v 1.10 92/01/09 12:40:34 drapeau Exp Locker: derek $";
  109.  
  110. #include "dtr.h"
  111. #include "dtr_ui.h"
  112.  
  113. /*
  114.  * Various Windows.
  115.  */
  116. extern  dtr_mainWindow_objects       *dtr_mainWindow;
  117.  
  118. /*
  119.  * Scrollbars
  120.  */
  121. Scrollbar    WaveCanvasScrollbar;
  122. Scrollbar       ScaleCanvasScrollbar;
  123. int            ScrollbarPixelsPerUnit;
  124. int             ScrollbarViewStart;
  125. int         ScrollbarViewEnd;
  126.  
  127. /*
  128.  * Global variables for Wave Canvas;
  129.  */
  130. Window         xidWave;
  131. Xv_Window      paintWinWave;
  132. Display        *dpyWave;
  133. GC             gcWave;
  134. int            viewStart;
  135. unsigned long *    WaveCanvasColormap;
  136.  
  137. /*
  138.  *  Global variables for VU Meter Canvas
  139.  */
  140. int             oldVUMeterLevel;
  141. Window        xidVUMeter;
  142. Xv_window    paintWinVUMeter;
  143. Display        *dpyVUMeter;
  144. GC        gcVUMeter;
  145. unsigned long * VUMeterCanvasColormap;
  146. #define REDLEVELSTART 72
  147.  
  148. /*
  149.  *  Global variables for Scale canvas.  The subscript "Scale" in 
  150.  *  these variables refer to the Scale canvas, but not literally
  151.  *  to some "scale".
  152.  */
  153. Window          xidScale;
  154. Xv_Window       paintWinScale;
  155. Display         *dpyScale;
  156. GC              gcScale;
  157. unsigned long * ScaleCanvasColormap;
  158. int             ScaleAxisHeight;
  159. int             ScaleTimeHeight;
  160.  
  161.  
  162. Notify_value
  163.   WaveCanvasScrollbarHandler(win, event, arg, type)
  164. Xv_window win;
  165. Event     *event;
  166. Notify_arg arg;
  167. Notify_event_type type;
  168. {
  169.   int    ie;
  170.   int    newViewStart;
  171.   
  172.   ie = event_id(event);
  173.   
  174.   switch(ie) 
  175.   {
  176.    case SCROLLBAR_REQUEST:
  177.     UpdateCanvasFrame();
  178.     newViewStart = xv_get(WaveCanvasScrollbar, SCROLLBAR_VIEW_START);
  179.     xv_set(ScaleCanvasScrollbar, SCROLLBAR_VIEW_START, newViewStart, NULL);
  180.     break;
  181.    default:
  182.     break;
  183.   }
  184.   return notify_next_event_func(win, (Notify_event)event, arg, type);
  185. }
  186.  
  187.  
  188. void
  189.   InitWaveCanvas()
  190. {
  191.   Xv_opaque       wcanvas = dtr_mainWindow->waveCanvas;
  192.   
  193.   EVENT("Init_Wave_Canvas");
  194.   
  195.   paintWinWave = canvas_paint_window(wcanvas);
  196.   xidWave = (Window) xv_get(paintWinWave, XV_XID);
  197.   dpyWave = (Display *) xv_get(wcanvas, XV_DISPLAY);
  198.   gcWave = XCreateGC(dpyWave, xidWave, 0, 0);
  199.   
  200.   xv_set(paintWinWave, WIN_CONSUME_EVENTS, WIN_NO_EVENTS,        /*  Specifies that only the left- and the right-..  */
  201.      LOC_WINENTER,                            /*  ...button eventw will be registered, in fact... */
  202.      LOC_WINEXIT,                            /*  ...useless because middle buttons events will.. */
  203.      WIN_ASCII_EVENTS,                        /*  ...appear anyways.                              */
  204.      LOC_DRAG, MS_LEFT, 
  205.      MS_MIDDLE, NULL, NULL);
  206.   
  207.   WaveCanvasColormap = GetColormap(wcanvas);                /*  Get colormap.                                   */
  208.   XSetForeground(dpyWave, gcWave, 
  209.          GetColorIndex(WaveCanvasColormap, "White"));
  210.   
  211.   oldLeftFloatMarker = -1.0;                        /*  Init left and right wave canvas markers.        */
  212.   oldRightFloatMarker = -1.0;
  213.   WaveCanvasRightMarkerSet = FALSE;
  214.   
  215.   WaveCanvasWidth = (int) xv_get(wcanvas, CANVAS_WIDTH, NULL);
  216.  
  217.   WaveCanvasHeight = (int) xv_get(wcanvas, CANVAS_HEIGHT, NULL);
  218.   WaveWindowWidth = (int) xv_get(wcanvas, XV_WIDTH, NULL);
  219.   WaveWindowHeight = (int) xv_get(wcanvas, XV_HEIGHT, NULL);
  220.   WaveCanvasMidHeight = WaveCanvasHeight/2;
  221.   WaveScopeWidth = WaveCanvasMidHeight - 4;
  222.   WaveCanvasInitReady = TRUE;
  223.   leftButtonHoldPoint = NOTREADY;
  224.   
  225.   DefaultWaveCanvasDataSamplingInterval = DEVICE_SAMPLE_RATE /        /*  Define Default DataSampling Interval --- we...  */
  226.     (WaveWindowWidth /                            /*  ...want the length of the wave window to be...  */
  227.      10.0);                                /*  ...equal to 10 seconds.                         */
  228.   
  229.   InitScaleCanvas();                            /*  Process to initialize the scale canvas.         */
  230.  
  231.   FrameStartingSecond = 0.0;                        /*  Initialize FrameStartingSecond.                 */
  232. }
  233.  
  234.  
  235. /*
  236.  *  Initialize wave canvas scrollbar (and implicitly initialize
  237.  *  the scale canvas scrollbar also)
  238.  */
  239. void
  240.   InitWaveCanvasScrollbar()
  241. {
  242.   Notify_value  WaveCanvasScrollbarHandler();
  243.   Canvas    canvas = dtr_mainWindow->waveCanvas;
  244.   
  245.   EVENT("Init_Wave_Canvas_Scrollbar");
  246.   
  247.   xv_set(canvas, CANVAS_WIDTH, MAX_ZOOM*xv_get(canvas, XV_WIDTH,    /*  Set Canvas parameters to allow for scrolling.   */
  248.                            NULL),
  249.      CANVAS_HEIGHT, xv_get(canvas, XV_HEIGHT, NULL),
  250.      CANVAS_AUTO_EXPAND, FALSE,
  251.      CANVAS_AUTO_SHRINK, FALSE,
  252.      NULL);  
  253.   
  254.   Zoom = 1.0;                                /*  Create scrollbar for Wave Canvas.               */
  255.   ScrollbarPixelsPerUnit = 10;
  256.   WaveCanvasDataSamplingInterval = DefaultWaveCanvasDataSamplingInterval /
  257.     Zoom;
  258.   WaveCanvasScrollbar = xv_create(dtr_mainWindow->waveCanvas, SCROLLBAR,
  259.                   SCROLLBAR_DIRECTION, SCROLLBAR_HORIZONTAL, 
  260.                   SCROLLBAR_PIXELS_PER_UNIT, ScrollbarPixelsPerUnit,
  261.                   SCROLLBAR_VIEW_LENGTH, 
  262.                   irint(xv_get(canvas, XV_WIDTH, NULL)/
  263.                     ((double)ScrollbarPixelsPerUnit)),
  264.                   SCROLLBAR_OBJECT_LENGTH, 
  265.                   irint(xv_get(canvas, XV_WIDTH, NULL)/
  266.                     ((double)ScrollbarPixelsPerUnit)),
  267.                   SCROLLBAR_PAGE_LENGTH,
  268.                   irint(xv_get(canvas, XV_WIDTH, NULL)/
  269.                     ((double)ScrollbarPixelsPerUnit)),
  270.                   NULL);
  271.   
  272.   notify_interpose_event_func(xv_get(WaveCanvasScrollbar, 
  273.                      SCROLLBAR_NOTIFY_CLIENT), 
  274.                   WaveCanvasScrollbarHandler,
  275.                   NOTIFY_SAFE); 
  276. }
  277.  
  278.  
  279. /*
  280.  *  This function is called by InitWaveCanvas() (not by main()) to
  281.  *  initialize the Scale Canvas.
  282.  */
  283. void
  284.   InitScaleCanvas()
  285. {
  286.   Xv_opaque            scanvas = dtr_mainWindow->scaleCanvas;
  287.   int                  newCanvasWidth;
  288.  
  289.   EVENT("Init_Scale_Canvas");
  290.   
  291.   ScaleAxisHeight = 17;
  292.   ScaleTimeHeight = 33;
  293.   paintWinScale = canvas_paint_window(scanvas);
  294.   xidScale = (Window)xv_get(paintWinScale, XV_XID);
  295.   dpyScale = (Display *) xv_get(scanvas, XV_DISPLAY);
  296.   
  297.   gcScale = XCreateGC(dpyScale, xidScale, 0, 0);
  298.   
  299.   ScaleCanvasColormap = GetColormap(scanvas);                /*  Get colormap.                                   */
  300.   ScaleCanvasPenColor("black");
  301. }
  302.  
  303.  
  304. /*
  305.  *  Initialize the Scale canvas Scrollbar which is not
  306.  *  going to be shown.
  307.  */
  308. void
  309.   InitScaleCanvasScrollbar()
  310. {
  311.   Notify_value  ScaleCanvasScrollbarHandler();
  312.   Canvas    scanvas = dtr_mainWindow->scaleCanvas;
  313.   
  314.   EVENT("Init_Scale_Canvas_Scrollbar");
  315.   
  316.   xv_set(scanvas, CANVAS_WIDTH, MAX_ZOOM*xv_get(scanvas, XV_WIDTH,  /*  Set Canvas parameters to allow for scrolling.   */
  317.                            NULL),
  318.      CANVAS_HEIGHT, xv_get(scanvas, XV_HEIGHT, NULL),
  319.      CANVAS_AUTO_EXPAND, FALSE,
  320.      CANVAS_AUTO_SHRINK, FALSE,
  321.      NULL);  
  322.   
  323.   ScaleCanvasScrollbar =xv_create(dtr_mainWindow->scaleCanvas,   /*  Create Scrollbar for ScaleCanvas.               */
  324.                   SCROLLBAR,
  325.                   SCROLLBAR_DIRECTION, 
  326.                   SCROLLBAR_HORIZONTAL, 
  327.                   NULL);
  328.   
  329.   xv_set(ScaleCanvasScrollbar, XV_SHOW, FALSE, NULL);            /*  Do not show scrollbar.                          */
  330. }
  331.  
  332.  
  333. /*
  334.  *  Update both the wave canvas and the scale canvas, as well as the 
  335.  *  scrollbar.
  336.  */
  337. void
  338.   UpdateCanvasesAndScrollbarParameters()
  339. {
  340.   int  newCanvasWidth;
  341.   
  342.   if (irint(Buffer.hdr.data_size / WaveCanvasDataSamplingInterval) 
  343.       < WaveWindowWidth)  
  344.   {
  345.     newCanvasWidth = WaveWindowWidth;                    /*  newCanvasWidth is the virtual canvas width: ie..*/
  346.   }                                    /*  ...it is usually part of the real canvas which..*/
  347.   else                                    /*  ...is MAX_ZOOM * WaveWindowWidth in length.     */
  348.   {
  349.     newCanvasWidth = WaveWindowWidth * Zoom;
  350.   }
  351.   
  352.   WaveCanvasWidth = newCanvasWidth;
  353.  
  354.   xv_set(WaveCanvasScrollbar,                        /*  Update Scrollbars.                              */
  355.      SCROLLBAR_PIXELS_PER_UNIT, ScrollbarPixelsPerUnit, 
  356.      SCROLLBAR_VIEW_LENGTH, irint(((double)WaveWindowWidth)/
  357.                       ScrollbarPixelsPerUnit),
  358.      SCROLLBAR_OBJECT_LENGTH, irint((double) newCanvasWidth / 
  359.                     ScrollbarPixelsPerUnit),
  360.      SCROLLBAR_PAGE_LENGTH, irint(((double)WaveWindowWidth)/
  361.                       ScrollbarPixelsPerUnit),
  362.      NULL);
  363.   xv_set(ScaleCanvasScrollbar, 
  364.      SCROLLBAR_PIXELS_PER_UNIT, ScrollbarPixelsPerUnit, 
  365.      SCROLLBAR_VIEW_LENGTH, irint(((double)WaveWindowWidth)/
  366.                       ScrollbarPixelsPerUnit),
  367.      SCROLLBAR_OBJECT_LENGTH, irint((double) newCanvasWidth / 
  368.                     ScrollbarPixelsPerUnit),
  369.      SCROLLBAR_PAGE_LENGTH, irint(((double)WaveWindowWidth)/
  370.                       ScrollbarPixelsPerUnit),
  371.      NULL);
  372. }    
  373.  
  374.  
  375. void
  376.   RepaintWaveCanvas()
  377. {
  378.   EVENT("Repaint_Wave_Canvas");
  379.   
  380.   WaveCanvasRepaintHandler((Canvas)dtr_mainWindow->waveCanvas, 
  381.                paintWinWave, (Display *)dpyWave,
  382.                xidWave, NULL);
  383.   
  384.   ScaleCanvasRepaintHandler((Canvas)dtr_mainWindow->scaleCanvas,
  385.                 paintWinScale, (Display *)dpyScale,
  386.                 xidScale, NULL);
  387. }
  388.  
  389.  
  390. void
  391.   InitVUMeterCanvas()
  392. {
  393.   Xv_opaque        vucanvas = dtr_mainWindow->vuMeterCanvas;
  394.   XGCValues        gcv;
  395.   int            dash_offset = 0;
  396.   static char        long_dashed[2] = {10,2};
  397.   
  398.   EVENT("Init_VU_Meter_Canvas");
  399.   
  400.   paintWinVUMeter = canvas_paint_window(vucanvas);
  401.   xidVUMeter = (Window)xv_get(paintWinVUMeter, XV_XID);
  402.   dpyVUMeter = (Display *) xv_get(vucanvas, XV_DISPLAY);
  403.   
  404.   gcv.line_style = LineOnOffDash;
  405.   gcv.line_width = 20;
  406.   gcVUMeter = XCreateGC(dpyVUMeter, xidVUMeter, GCLineStyle, &gcv);
  407.   XSetDashes(dpyVUMeter, gcVUMeter, dash_offset, long_dashed, 2);
  408.   XSetLineAttributes(dpyVUMeter, gcVUMeter, gcv.line_width, 
  409.              gcv.line_style, CapButt, JoinRound);
  410.   
  411.   VUMeterCanvasColormap = GetColormap(vucanvas);            /*  Get colormap.                                   */
  412.   
  413.   oldVUMeterLevel = 0;                            /*  Initialize VU Meter level.                      */
  414.   
  415.   VUMeterCanvasPenColor("Forest Green");                /*  Draw some dark red and green colors onto the... */
  416.   XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter,                /*  ...meter initially.                             */
  417.         7+0, 15,
  418.         7+REDLEVELSTART, 15);
  419.   VUMeterCanvasPenColor("brown");
  420.   XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  421.         7+REDLEVELSTART, 15,
  422.         7+128, 15);
  423.   
  424. }
  425.  
  426.  
  427. /*
  428.  *  DisplayVUMeter(): 
  429.  *  Brief description of the algorithm:
  430.  *  If the new sound level is higher than before, paint "difference" area with
  431.  *  pen_color (green).  Else, if new sound level is lower than before,
  432.  *  paint "difference" area with black.
  433.  */
  434. void
  435.   DisplayVUMeter(startpos)
  436. int  startpos;
  437. {
  438.   register int        i;
  439.   int            level;
  440.   int            end;
  441.   unsigned char        data;
  442.   static unsigned char  soundData[SCOPE_WIDTH];
  443.   
  444.   EVENT("Display_VU_Meter");
  445.   
  446.   if (startpos < 0)  
  447.   {
  448.     i = -startpos;
  449.     startpos = 0;
  450.   }
  451.   else i = startpos;
  452.   
  453.   end = SCOPE_WIDTH + startpos;
  454.   
  455.   if (FileReady)
  456.   {
  457.     soundfd = open(Buffer.filename, O_RDONLY);
  458.     lseek(soundfd, Buffer.hdr_size + i, L_SET);
  459.     read(soundfd, &soundData, SCOPE_WIDTH);
  460.     close(soundfd);
  461.     
  462.     for (level = 0; i < end && i < Buffer.hdr.data_size; i++)        
  463.     {
  464.       data = soundData[i - startpos];
  465.       if (abs((int)audio_u2c(data)) > level)                /*  Taking the MAX.                                 */
  466.     level = abs((int)audio_u2c(data));
  467.     }
  468.   }
  469.   else 
  470.   {
  471.     for (level = 0; i < end && i < Buffer.hdr.data_size; i++)        
  472.     {
  473.       if (abs((int)audio_u2c(Buffer.data[i])) > level)            /*  Taking the MAX.                                 */
  474.     level = abs((int)audio_u2c(Buffer.data[i]));
  475.     }
  476.   }
  477.   
  478.   level = ((level/12)+1)*12;
  479.   
  480.   if (oldVUMeterLevel < level)
  481.   {
  482.     if (oldVUMeterLevel > REDLEVELSTART) 
  483.     {
  484.       VUMeterCanvasPenColor("Red");   
  485.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  486.         7+oldVUMeterLevel, 15,
  487.         7+level, 15);
  488.     }
  489.     else if (level > REDLEVELSTART) 
  490.     {
  491.       VUMeterCanvasPenColor("Green");
  492.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  493.         7+oldVUMeterLevel, 15,
  494.         7+REDLEVELSTART, 15);
  495.       VUMeterCanvasPenColor("Red");   
  496.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  497.         7+REDLEVELSTART, 15,
  498.         7+level, 15);
  499.     }
  500.     else 
  501.     {
  502.       VUMeterCanvasPenColor("Green");
  503.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  504.         7+oldVUMeterLevel, 15,
  505.         7+level, 15);
  506.     }
  507.   } 
  508.   else if (oldVUMeterLevel > level) 
  509.   {
  510.     if (level < REDLEVELSTART && REDLEVELSTART <= oldVUMeterLevel) 
  511.     {
  512.       VUMeterCanvasPenColor("Forest Green");
  513.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  514.         7+level, 15,
  515.         7+REDLEVELSTART, 15);
  516.       VUMeterCanvasPenColor("brown");
  517.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  518.         7+REDLEVELSTART, 15,
  519.         7+oldVUMeterLevel, 15);
  520.     }
  521.     else if (level >= REDLEVELSTART) 
  522.     {
  523.       VUMeterCanvasPenColor("brown");
  524.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  525.         7+level, 15,
  526.         7+oldVUMeterLevel, 15);
  527.     } 
  528.     else 
  529.     {
  530.       VUMeterCanvasPenColor("Forest Green");
  531.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  532.         7+level, 15,
  533.         7+oldVUMeterLevel, 15);
  534.     }
  535.   }
  536.   
  537.   oldVUMeterLevel = level;
  538. }                                    /* end function DisplayVUMeter */
  539.  
  540.  
  541. /*
  542.  *  Clear Wave Canvas, reset the scrollbars.
  543.  */
  544. void
  545.   ResetWaveCanvas()
  546. {
  547.   ClearWaveCanvas();                            /*  Clear Wave Canvas and the Scale Canvas.         */
  548.   ClearScaleCanvas();
  549.   xv_set(WaveCanvasScrollbar, SCROLLBAR_VIEW_START, 0, NULL);        /*  Reset the canvas scrollbar.                     */
  550.   ScrollbarViewStart = ScrollbarViewEnd = 0;
  551.   if (xv_get(dtr_mainWindow->zoomSlider, PANEL_VALUE) != 10)        /*  Reset the zoom slider.                          */
  552.     xv_set(dtr_mainWindow->zoomSlider, PANEL_VALUE, 10, NULL);
  553.   Zoom = 1.0;
  554.   oldLeftFloatMarker = oldRightFloatMarker = -1.0;            /*  Reset Various Selection parameters.             */
  555.   WaveCanvasRightMarkerSet = FALSE;
  556.   leftButtonHoldPoint = NOTREADY;
  557. }                                    /* end function ResetWaveCanvas */
  558.  
  559.  
  560. void
  561.   UpdateVUMeter()
  562. {
  563.   int        display_position;
  564.   unsigned    s;
  565.   int        i;
  566.   short        try;
  567.   short        last;
  568.   unsigned char data;
  569.   
  570.   EVENT("UpdateVUMeter");
  571.   
  572.   if (Buffer.hdr.data_size == 0)
  573.     return;
  574.   
  575.   if (ActiveFlag & RECORD)                        /*  Recording.                                      */
  576.   {    
  577.     display_position =                            /*  Display the next piece of data.  We only want   */
  578.       (Buffer.hdr.data_size - SCOPE_WIDTH) & ~SCOPE_MASK;        /*  to display full panels of data.                 */
  579.     if (display_position < 0) 
  580.     {
  581.       display_position = 0;
  582.     }
  583.   } 
  584.   else if (ActiveFlag & PLAY)                        /*  Playing.                                        */
  585.   {
  586.     s = 0;                                /*  Now display the scope waveform.  We want to...  */
  587.     (void) audio_get_play_samples(Audio_fd, &s);            /*  ...display starting at a multiple of 256 (the.. */
  588.     if (Buffer.play.start != Buffer.play.end)                /*  ...scope window size).  If we are not at the... */
  589.     {                                    /*  ...next such boundary, return w/o doing...      */
  590.       display_position = (Buffer.play.start +                /*  ...anything.                                    */
  591.               (s % (Buffer.play.end - 
  592.                 Buffer.play.start)))
  593.     & ~SCOPE_MASK;
  594.     }
  595.     else 
  596.     {
  597.       display_position = Buffer.play.start & ~SCOPE_MASK;
  598.     }
  599.   } 
  600.   else 
  601.   {
  602.     display_position = Buffer.display.last;                /*  Inactive.                                       */
  603.     DisplayVUMeter(display_position);                    /*  Repair damage.                                  */
  604.     return;
  605.   }
  606.   
  607.   if (FileReady)
  608.   {
  609.     data = GetFileData(display_position);
  610.     last = audio_u2s(data);
  611.   }
  612.   else
  613.   {
  614.     last = audio_u2s(Buffer.data[display_position]);            /*  Look for a rising edge at a zero-crossing.      */
  615.   }
  616.   
  617.   for (i = display_position - 1;
  618.        (i >= 0) && (i > (display_position - (SCOPE_WIDTH / 2)));
  619.        i--)
  620.   {
  621.     if (FileReady)
  622.     {
  623.       data = GetFileData(i);
  624.       try = audio_u2s(data);
  625.     }
  626.     else
  627.     {
  628.       try = audio_u2s(Buffer.data[i]);
  629.     }
  630.     
  631.     if ((try < last) && (last >= 0) && (try <= 0)) 
  632.     {
  633.       if (last < ((try < 0) ? -try : try))
  634.     i++;
  635.       display_position = i;
  636.       break;
  637.     }
  638.     last = try;
  639.   }
  640.   
  641.   if (display_position != Buffer.display.last) 
  642.   {
  643.     DisplayVUMeter(display_position);
  644.     Buffer.display.last = display_position;
  645.   }
  646. }
  647.  
  648.  
  649. void
  650.   ClearWaveCanvas()
  651. {
  652.   extern   GC gcWave;
  653.   double   scaleMarkerInterval;
  654.   double   x;
  655.  
  656.   Zoom = 1.0;
  657.   
  658.   XClearWindow(dpyWave, xidWave);
  659.   scaleMarkerInterval = WaveWindowWidth / 10.0 * Zoom;            /*  Draw the horizontal time axis.                  */
  660.   WaveCanvasPenColor("Red");
  661.   
  662.   XDrawLine(dpyWave, xidWave, gcWave, 0, WaveCanvasMidHeight-15, 
  663.         WaveCanvasWidth, WaveCanvasMidHeight-15);
  664.   for(x = 0.0 ; x < (double) WaveCanvasWidth ; x += scaleMarkerInterval)
  665.     XDrawLine(dpyWave, xidWave, gcWave, 
  666.           irint(x), WaveCanvasMidHeight-15+5,
  667.           irint(x), WaveCanvasMidHeight-15-5);
  668. }
  669.  
  670.  
  671. void
  672.   ClearScaleCanvas()
  673. {
  674.   extern   GC gcScale;
  675.   
  676.   XClearWindow(dpyScale, xidScale);
  677.   ScaleCanvasPenColor("black");
  678.   XDrawLine(dpyScale, xidScale, gcScale, 0, ScaleAxisHeight, 
  679.         WaveCanvasWidth-1, ScaleAxisHeight);
  680.   Zoom = 1.0;
  681.   ScaleCanvasRepaintHandler((Canvas)dtr_mainWindow->scaleCanvas,
  682.                 paintWinScale, dpyScale, xidScale, NULL);
  683. }
  684.  
  685.  
  686. /*
  687.  *  Check if the user has clicked the mouse at a place outside
  688.  *  the scope of the soundbuffer.
  689.  */
  690. BOOL
  691.   WaveCanvasOutOfSoundScope(winX)
  692. int winX;
  693. {
  694.   int bufferX;
  695.   
  696.   if (WaveCanvasDataSamplingInterval == 0.0)
  697.     return (TRUE);
  698.   
  699.   bufferX = irint(winX * WaveCanvasDataSamplingInterval);
  700.   
  701.   if (bufferX > Buffer.hdr.data_size || bufferX < 0)
  702.     return(TRUE);
  703.   return(FALSE);
  704. }
  705.  
  706.  
  707. /*
  708.  *  The winX here is the overall x-coord under the current Zoom value.
  709.  */
  710. void
  711.   WaveCanvasMarkerHandler(winX, oldmarker)
  712. int winX;
  713. double *oldmarker;
  714. {
  715.   int     oldLeftWinX, oldRightWinX, LeftWinX, RightWinX;
  716.   
  717.   EVENT("Marker_Handler");
  718.   
  719.   if (WaveCanvasOutOfSoundScope(winX))
  720.     return;
  721.   
  722.   oldLeftWinX = irint(oldLeftFloatMarker /                /*  Save old markers.                               */
  723.               WaveCanvasDataSamplingInterval);
  724.   oldRightWinX = irint(oldRightFloatMarker /
  725.                WaveCanvasDataSamplingInterval);
  726.   
  727.   if (oldmarker == &oldLeftFloatMarker)                    /*  Left button or Right button pressed.            */
  728.   {
  729.     oldLeftFloatMarker = oldRightFloatMarker = winX * 
  730.       WaveCanvasDataSamplingInterval;
  731.   } 
  732.   else 
  733.   {
  734.     oldRightFloatMarker = winX * WaveCanvasDataSamplingInterval;
  735.   }
  736.  
  737.   LeftWinX = irint( oldLeftFloatMarker /                /*  Draw markers.                                   */
  738.            WaveCanvasDataSamplingInterval );
  739.   RightWinX = irint( oldRightFloatMarker / 
  740.             WaveCanvasDataSamplingInterval );            
  741.   
  742.   if (!WaveCanvasRightMarkerSet && oldmarker == 
  743.       &oldRightFloatMarker)
  744.     ReverseWaveCanvasArea(winX, winX);
  745.  
  746. /**********
  747.     ReverseWaveCanvasArea(winX, winX);
  748. **********/
  749.   
  750.   if (LeftWinX > oldRightWinX || RightWinX < oldLeftWinX) 
  751.   {
  752.     if (WaveCanvasRightMarkerSet) 
  753.     {
  754.       ReverseWaveCanvasArea(oldLeftWinX, oldRightWinX);
  755.       if (oldmarker == &oldLeftFloatMarker)
  756.     ReverseWaveCanvasArea(winX, winX);
  757. /**********
  758.     ReverseWaveCanvasArea(winX, winX);
  759. **********/
  760.     }
  761.   }
  762.   else if (WaveCanvasRightMarkerSet) 
  763.   {
  764.     if (LeftWinX > oldLeftWinX)
  765.     {
  766.       ReverseWaveCanvasArea(oldLeftWinX, LeftWinX-1);
  767.     } 
  768.     else if (LeftWinX < oldLeftWinX) 
  769.     {
  770.       ReverseWaveCanvasArea(LeftWinX, oldLeftWinX-1);
  771.     }
  772.     
  773.     if (RightWinX > oldRightWinX) 
  774.     {
  775.       ReverseWaveCanvasArea(oldRightWinX + 1, RightWinX);
  776.     } 
  777.     else if (RightWinX < oldRightWinX) 
  778.     {
  779.       ReverseWaveCanvasArea(RightWinX + 1, oldRightWinX);
  780.     }
  781.   }
  782.   
  783.   if (oldmarker == &oldRightFloatMarker)
  784.     WaveCanvasRightMarkerSet = TRUE;
  785.   
  786.   Buffer.play.start = irint(oldLeftFloatMarker);            /*  Update start and end points.                    */
  787.   Buffer.play.end = irint(oldRightFloatMarker);
  788.   
  789.   UpdateMessageDisplay();                        /*  Update message display (sound selection size,.. */
  790.                                     /*  ...duration etc.) */
  791. }
  792.  
  793.  
  794. /*
  795.  *  Takes cares of case when user tries to drag leftwards (instead of 
  796.  *  rightwards).
  797.  */
  798. void
  799.   WaveCanvasBackwardMarkerHandler(winX, oldmarker)
  800. int  winX;
  801. double *oldmarker;
  802. {
  803.   int     oldLeftWinX, oldRightWinX, LeftWinX, RightWinX;
  804.   
  805.   EVENT("Wave_Canvas_Marker_Handler");
  806.   
  807.   if (WaveCanvasOutOfSoundScope(winX))
  808.     return;
  809.   
  810.   oldLeftWinX = irint( oldLeftFloatMarker /                /*  Save old markers.                               */
  811.               WaveCanvasDataSamplingInterval );
  812.   oldRightWinX = irint( oldRightFloatMarker / 
  813.                WaveCanvasDataSamplingInterval );
  814.   
  815.   if (oldmarker == &oldLeftFloatMarker) 
  816.   {                                    /*  Left button or right button pressed.            */
  817.     oldLeftFloatMarker = winX * WaveCanvasDataSamplingInterval;
  818.   } 
  819.   
  820.   LeftWinX = irint( oldLeftFloatMarker /                /*  Draw markers.                                   */
  821.            WaveCanvasDataSamplingInterval );
  822.   RightWinX = irint( oldRightFloatMarker / 
  823.             WaveCanvasDataSamplingInterval );
  824.   
  825.   if (!WaveCanvasRightMarkerSet && oldmarker == &oldRightFloatMarker)
  826.     ReverseWaveCanvasArea(winX, winX);
  827.   
  828.   if (LeftWinX > oldRightWinX || RightWinX < oldLeftWinX) 
  829.   {
  830.     if (WaveCanvasRightMarkerSet)
  831.       ReverseWaveCanvasArea(oldLeftWinX, oldRightWinX);
  832.     if (oldmarker == &oldLeftFloatMarker)
  833.       ReverseWaveCanvasArea(winX, winX);
  834.   }
  835.   else if (WaveCanvasRightMarkerSet) 
  836.   {
  837.     if (LeftWinX > oldLeftWinX && oldLeftWinX != 0) 
  838.     {
  839.       ReverseWaveCanvasArea(oldLeftWinX, LeftWinX-1);
  840.     } 
  841.     else if (LeftWinX < oldLeftWinX) 
  842.     {
  843.       ReverseWaveCanvasArea(LeftWinX, oldLeftWinX-1);
  844.     }
  845.     
  846.     if (RightWinX > oldRightWinX) 
  847.     {
  848.       ReverseWaveCanvasArea(oldRightWinX + 1, RightWinX);
  849.     } 
  850.     else if (RightWinX < oldRightWinX) 
  851.     {
  852.       ReverseWaveCanvasArea(RightWinX + 1, oldRightWinX);
  853.     }
  854.   }
  855.   
  856.   WaveCanvasRightMarkerSet = TRUE;
  857.   
  858.   Buffer.play.start = irint(oldLeftFloatMarker);            /*  Update start and end points.                    */
  859.   Buffer.play.end = irint(oldRightFloatMarker);
  860.   
  861.   UpdateMessageDisplay();                        /*  Update message display (sound selection size... */
  862.                                     /*  ...and duration).                               */
  863. }
  864.  
  865.  
  866. int
  867.   GetColorIndex(colormap, colorString)
  868. unsigned long *colormap;
  869. char *colorString;
  870. {
  871.   return(colormap[gcm_color_index(colorString)]);
  872. }
  873.  
  874.  
  875. /*
  876.  *  An inverse mapping to retrieve the true colormap defined
  877.  *  by guide.
  878.  */
  879. unsigned long *
  880.   GetColormap(win)
  881. Xv_opaque win;
  882. {
  883.   unsigned long *colors;
  884.   Cms  cms;
  885.   Xv_Screen  screen;
  886.   
  887.   screen = (Xv_Screen) XV_SCREEN_FROM_WINDOW(win);
  888.   cms = (Cms) xv_find(screen, CMS, CMS_NAME, gcm_colormap_name(),
  889.               XV_AUTO_CREATE, FALSE, 0);
  890.   colors = (unsigned long *) xv_get(cms, CMS_INDEX_TABLE);
  891.   return (colors);
  892. }
  893.  
  894.  
  895. /*
  896.  *  Set Foreground color of wave canvas.
  897.  */
  898. void
  899.   WaveCanvasPenColor(colorStr)
  900. char *colorStr;
  901. {
  902.   XSetForeground(dpyWave, gcWave, 
  903.          GetColorIndex(WaveCanvasColormap, colorStr));
  904. }
  905.  
  906.  
  907. /*
  908.  *  Set Foreground color of wave canvas.
  909.  */
  910. void
  911.   ScaleCanvasPenColor(colorStr)
  912. char *colorStr;
  913. {
  914.   XSetForeground(dpyScale, gcScale,
  915.          GetColorIndex(ScaleCanvasColormap, colorStr));
  916. }
  917.  
  918.  
  919. /*
  920.  *  Set Foreground color of VU Meter.
  921.  */
  922. void
  923.   VUMeterCanvasPenColor(colorStr)
  924. char *colorStr;
  925. {
  926.   XSetForeground(dpyVUMeter, gcVUMeter,
  927.          GetColorIndex(VUMeterCanvasColormap, colorStr));
  928. }
  929.  
  930.  
  931. /*
  932.  *  Reset VU Meter parameters.
  933.  */
  934. void
  935.   ResetVUMeter()
  936. {
  937.   oldVUMeterLevel = 0;
  938. }
  939.  
  940.  
  941. void
  942.   ClearVUMeterCanvas()
  943. {
  944.   XClearWindow(dpyVUMeter, xidVUMeter);
  945.   
  946.   VUMeterCanvasPenColor("Forest Green");                /*  Draw some dark red and green colors onto the... */
  947.   XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter,                /*  ...meter initially.                             */
  948.         7+0, 15,
  949.         7+REDLEVELSTART, 15);
  950.   VUMeterCanvasPenColor("brown");
  951.   XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  952.         7+REDLEVELSTART, 15,
  953.         7+132, 15);
  954. }
  955.  
  956.  
  957. /*
  958.  *  This function is called when user selects "Reset Markers"
  959.  *  from the function menu.
  960.  */
  961. void
  962.   ResetWaveCanvasMarkers()
  963. {
  964.   EVENT("Reset_Wave_Canvas_Markers");
  965.   
  966.   ReverseWaveCanvasArea(irint(oldLeftFloatMarker/
  967.                   WaveCanvasDataSamplingInterval),
  968.             irint(oldRightFloatMarker/
  969.                   WaveCanvasDataSamplingInterval));
  970.   WaveCanvasRightMarkerSet = FALSE;
  971.   leftButtonHoldPoint = NOTREADY;
  972.   UpdateMessageDisplay();
  973.   UpdateSelection();
  974.   Buffer.play.start = 0;
  975.   Buffer.play.end = Buffer.hdr.data_size - 1;
  976. }
  977.  
  978.  
  979. /*
  980.  *  When user chooses "Clear All" from the menu.
  981.  */
  982. void
  983.   ClearAllSound()
  984. {
  985.   ResetWaveCanvas();
  986.   ResetGlobalWaveCanvas();
  987.   ClearMessageDisplay();
  988.   InitBuffer();
  989.   SoundBufferReady = FALSE;
  990.   SameSoundFile = FALSE;
  991.   FileReady = FALSE;
  992.   BufferSaved = TRUE;
  993.   currentSelectionReadyToPlay = FALSE;
  994.   sprintf(currentSoundFile,"Untitled");
  995.   UpdateHeader(FALSE);
  996.   UpdateSelection();
  997.   strcpy(Buffer.filename, "");
  998. }                                    /* end function ClearAllSound */
  999.  
  1000.  
  1001. /*
  1002.  *  For Highlighting or Unhighlighting a portion of the canvas.
  1003.  */
  1004. void
  1005.   ReverseWaveCanvasArea(left, right)
  1006. int  left, right;
  1007. {
  1008.   int   startReverseX;
  1009.   int   endReverseX;
  1010.   
  1011.   startReverseX = irint(left - (FrameStartingSecond * DEVICE_SAMPLE_RATE /
  1012.                 WaveCanvasDataSamplingInterval));
  1013.   if (startReverseX < 0)
  1014.     startReverseX = 0;
  1015.  
  1016.   endReverseX = irint(right - (FrameStartingSecond *  DEVICE_SAMPLE_RATE /
  1017.                    WaveCanvasDataSamplingInterval));
  1018.   
  1019.   if (endReverseX > WaveCanvasWidth)
  1020.     endReverseX = WaveCanvasWidth;
  1021.   
  1022.   XSetFunction(dpyWave, gcWave, GXinvert);
  1023.   XFillRectangle(dpyWave, xidWave, gcWave, 
  1024.          startReverseX, 0,
  1025.          endReverseX - startReverseX + 1, WaveWindowHeight - 1);
  1026.   XSetFunction(dpyWave, gcWave, GXcopy);
  1027. }
  1028.  
  1029.  
  1030. void
  1031.   CenterWaveCanvasHighlightedSegment()
  1032. {
  1033.   int              size;
  1034.   extern Scrollbar WaveCanvasScrollbar;
  1035.   extern int       ScrollbarPixelsPerUnit;
  1036.   int              newScrollbarViewStart;
  1037.   int              midPt;
  1038.   int              maxScrollbarViewStart;
  1039.   
  1040.   if (WaveCanvasRightMarkerSet) 
  1041.   {
  1042.     size = irint(oldRightFloatMarker - oldLeftFloatMarker);
  1043.  
  1044.     maxScrollbarViewStart = irint(floor(10.0 * DEVICE_SAMPLE_RATE /
  1045.                     WaveCanvasDataSamplingInterval / 
  1046.                     ScrollbarPixelsPerUnit));
  1047.  
  1048.     midPt = irint((((oldLeftFloatMarker + oldRightFloatMarker) / 2.0)
  1049.            - (FrameStartingSecond * DEVICE_SAMPLE_RATE)) /
  1050.           WaveCanvasDataSamplingInterval);
  1051.  
  1052.     if (midPt > WaveWindowWidth/2)                    /*  If midpt of highlighted portion is greater...   */
  1053.     {                                    /*  ...than the width of wave window, the slider... */
  1054.       if (irint(size/WaveCanvasDataSamplingInterval) <            /*  ...needs to be adjusted.                        */
  1055.       WaveWindowWidth) 
  1056.       {
  1057.     newScrollbarViewStart = (midPt - (WaveWindowWidth / 2)) / 
  1058.       ScrollbarPixelsPerUnit;
  1059.       }
  1060.       else 
  1061.       {
  1062.     newScrollbarViewStart = irint((oldLeftFloatMarker - (FrameStartingSecond * DEVICE_SAMPLE_RATE)) /
  1063.                       WaveCanvasDataSamplingInterval /
  1064.                       ScrollbarPixelsPerUnit);
  1065.       }
  1066.  
  1067.       if (newScrollbarViewStart < 0)
  1068.     newScrollbarViewStart = 0;
  1069.       if (newScrollbarViewStart > maxScrollbarViewStart)
  1070.     newScrollbarViewStart = maxScrollbarViewStart;
  1071.       
  1072.       xv_set(WaveCanvasScrollbar, SCROLLBAR_VIEW_START,
  1073.          newScrollbarViewStart, NULL);
  1074.     } 
  1075.     else 
  1076.     {
  1077.       xv_set(WaveCanvasScrollbar, SCROLLBAR_VIEW_START, 0, NULL);
  1078.     }
  1079.   }
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  *  Each Frame contains 10 seconds of data.  If the
  1085.  *  segment to be displayed exceeds 10 seconds, this 
  1086.  *  function cuts out the excess portions.
  1087.  */
  1088. void
  1089.   HighlightWaveCanvas()
  1090. {
  1091.   int    startReverseX;
  1092.   int    endReverseX;
  1093.  
  1094.   startReverseX = irint((oldLeftFloatMarker -
  1095.              (FrameStartingSecond * DEVICE_SAMPLE_RATE)) /
  1096.             WaveCanvasDataSamplingInterval);
  1097.   if (startReverseX < 0)
  1098.     startReverseX = 0;
  1099.   
  1100.   endReverseX = irint((oldRightFloatMarker -
  1101.                (FrameStartingSecond * DEVICE_SAMPLE_RATE)) /
  1102.               WaveCanvasDataSamplingInterval);
  1103.   if (endReverseX > WaveCanvasWidth)
  1104.     endReverseX = WaveCanvasWidth;
  1105.   
  1106.   ReverseWaveCanvasArea(startReverseX, endReverseX);
  1107. }
  1108.  
  1109.  
  1110. void
  1111.   CalculateLevelAndDisplayVUMeter(level)
  1112. int  level;
  1113. {
  1114.   level = ((level/12)+1)*12;
  1115.   
  1116.   if (oldVUMeterLevel < level) {
  1117.     if (oldVUMeterLevel > REDLEVELSTART) 
  1118.     {
  1119.       VUMeterCanvasPenColor("Red");   
  1120.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1121.         7+oldVUMeterLevel, 15,
  1122.         7+level, 15);
  1123.     }
  1124.     else if (level > REDLEVELSTART) 
  1125.     {
  1126.       VUMeterCanvasPenColor("Green");
  1127.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1128.         7+oldVUMeterLevel, 15,
  1129.         7+REDLEVELSTART, 15);
  1130.       VUMeterCanvasPenColor("Red");   
  1131.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1132.         7+REDLEVELSTART, 15,
  1133.         7+level, 15);
  1134.     }
  1135.     else 
  1136.     {
  1137.       VUMeterCanvasPenColor("Green");
  1138.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1139.         7+oldVUMeterLevel, 15,
  1140.         7+level, 15);
  1141.     }
  1142.   } 
  1143.   else if (oldVUMeterLevel > level) 
  1144.   {
  1145.     if (level < REDLEVELSTART && REDLEVELSTART <= oldVUMeterLevel) 
  1146.     {
  1147.       VUMeterCanvasPenColor("Forest Green");
  1148.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1149.         7+level, 15,
  1150.         7+REDLEVELSTART, 15);
  1151.       VUMeterCanvasPenColor("brown");
  1152.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1153.         7+REDLEVELSTART, 15,
  1154.         7+oldVUMeterLevel, 15);
  1155.     }
  1156.     else if (level >= REDLEVELSTART) 
  1157.     {
  1158.       VUMeterCanvasPenColor("brown");
  1159.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1160.         7+level, 15,
  1161.         7+oldVUMeterLevel, 15);
  1162.     } 
  1163.     else 
  1164.     {
  1165.       VUMeterCanvasPenColor("Forest Green");
  1166.       XDrawLine(dpyVUMeter, xidVUMeter, gcVUMeter, 
  1167.         7+level, 15,
  1168.         7+oldVUMeterLevel, 15);
  1169.     }
  1170.   }
  1171.   
  1172.   oldVUMeterLevel = level;                        
  1173. }                                    /* end function CalculateLevelAndDisplayVUMeter */
  1174.